# config.py
# -*- coding: utf-8 -*-

"""
项目配置文件
"""

import os
import re

# --- 基础路径配置 ---
# 项目根目录
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# 比对库文件夹（存放源文档）
CORPUS_DIR = os.path.join(BASE_DIR, 'corpus')
# 结果存储文件夹（存放报告、指标、中间文件等）
RESULT_DIR = os.path.join(BASE_DIR, 'result')
# 临时文件文件夹（例如上传文件临时存放）
TEMP_DIR = os.path.join(BASE_DIR, 'temp_files')
# 待检测文件输入目录
INPUT_DIR = os.path.join(BASE_DIR, 'input')
# 缓存文件夹（存放预处理后的文档数据）
CACHE_DIR = os.path.join(BASE_DIR, 'cache')
# 索引数据存储目录（存放 MinHash LSH、倒排、Faiss 等索引文件）
INDEX_DIR = os.path.join(BASE_DIR, 'index_data')

# OCR 识别的配置
MINERVA_UPLOAD_FOLDER = os.path.join(BASE_DIR, 'minerva_ocr', 'uploads_temp')
MINERVA_RESULTS_FOLDER = os.path.join(BASE_DIR, 'minerva_ocr', 'results_temp')
MINERVA_MAX_CONTENT_LENGTH = 300 * 1024 * 1024  # 最大上传文件大小限制 (300MB)
MINERVA_ALLOWED_PDF_EXTENSIONS = {'pdf'}
MINERVA_ALLOWED_IMAGE_EXTENSIONS = {'png', 'jpg', 'jpeg', 'bmp', 'tiff', 'gif'}


# 确保基础文件夹存在
# (在程序启动时创建，避免后续因目录不存在而出错)
os.makedirs(CORPUS_DIR, exist_ok=True)
os.makedirs(RESULT_DIR, exist_ok=True)
os.makedirs(TEMP_DIR, exist_ok=True)
os.makedirs(INPUT_DIR, exist_ok=True)
os.makedirs(CACHE_DIR, exist_ok=True)
os.makedirs(INDEX_DIR, exist_ok=True)
os.makedirs(MINERVA_UPLOAD_FOLDER, exist_ok=True)
os.makedirs(MINERVA_RESULTS_FOLDER, exist_ok=True)

# --- 核心检测参数 ---
# 最小匹配长度 (字符数)
MIN_MATCH_LENGTH = 10

# --- MinHash 预筛选配置 ---
# 是否启用 MinHash LSH 进行初步筛选，以减少需要详细比较的文档数量
USE_MINHASH_PRESCREENING = True
# 输入文本字符数阈值，当待检测文本的字符数少于此值时，将自动禁用 MinHash 初筛（因为短文本的 MinHash 可能不准确或意义不大）
MINHASH_INPUT_MIN_CHARS_THRESHOLD = 500
# MinHash 使用的置换函数数量 (影响签名精度和大小，通常 128 或 256)
MINHASH_NUM_PERM = 128
# LSH 预筛选的 Jaccard 相似度阈值 (0.0 到 1.0)，只有 Jaccard 相似度估计值高于此阈值的候选文档才会被选中进行下一步比较
MINHASH_THRESHOLD = 0.6
# MinHash 使用的字符 n-gram (分片 Shingle) 大小
MINHASH_SHINGLE_SIZE = 5


# --- 倒排索引 (Inverted Index) 配置 ---
# 是否启用倒排索引进行候选集召回 (主要用于快速定位可能包含相同短语的文档)
USE_INVERTED_INDEX = True
# 用于构建倒排索引的 N-gram 大小 (单位：字符)
INVERTED_INDEX_NGRAM_SIZE = 7
# 从输入文本中提取多少个 N-gram 用于查询倒排索引
INVERTED_INDEX_QUERY_NGRAM_COUNT = 20
# 构建索引时，忽略文档频率 (Document Frequency) 低于此值的 N-gram
INVERTED_INDEX_MIN_DF = 2
# 构建索引时，忽略文档频率高于此比例的 N-gram (0.0 到 1.0)
INVERTED_INDEX_MAX_DF_RATIO = 0.8 # 使用比例而非绝对值
# 倒排索引候选阈值，一个语料库文档至少匹配多少个查询 N-gram，才被认为是候选文档
INVERTED_INDEX_CANDIDATE_THRESHOLD = 3


# --- 语义向量索引 (Semantic Vector Index) 配置 ---
# 是否启用基于 Faiss 的语义向量索引进行候选集召回 (用于快速查找语义相似的文本块)
USE_SEMANTIC_INDEX = True
# 语义索引类型 (Faiss index factory string)
# "IDMap,Flat": 精确索引，IDMap 允许向量 ID 和原始数据关联，Flat 表示暴力搜索。适用于中小型数据集。
# "IDMap,IVF{nlist},Flat": 倒排文件索引，nlist 是聚类中心数量，需要训练。适用于大型数据集。
# "IDMap,HNSW{M}": 基于图的近似最近邻搜索，M 是邻居数量。适用于高维数据，性能较好。
# 选择哪种索引取决于数据集大小、所需精度和查询速度。内积 (IP) 通常用于归一化的嵌入向量。
FAISS_INDEX_TYPE = "IDMap,Flat" # 默认为精确搜索
# Faiss 索引训练样本数量 (仅当使用需要训练的索引类型如 IVF 时有效)
FAISS_TRAIN_SIZE = 100000
# Faiss 是否尝试使用 GPU (需要安装 faiss-gpu 且有可用 CUDA 环境)
FAISS_USE_GPU = False # 默认为 False，CPU 版本兼容性更好
# 每个输入块在语义索引中查询返回 Top K 个最相似的语料库块
SEMANTIC_INDEX_TOP_K = 50
# 语义索引候选阈值 (0.0 到 1.0)，在向量索引查询时，候选块与查询块的相似度（内积）必须高于此阈值才会被选中
SEMANTIC_INDEX_CANDIDATE_THRESHOLD = 0.5


# --- 语义相似度计算配置 ---
# 是否启用语义相似度计算（即使没有使用语义索引召回，也可以在候选集上进行计算）
USE_SEMANTIC_SIMILARITY = True
# 语义嵌入模型名称 (Hugging Face model hub 上的模型标识符)
SENTENCE_MODEL_NAME = 'shibing624/text2vec-base-chinese'
# 语义相似度阈值 (0.0 到 1.0)，计算得到的两个文本块的余弦相似度高于此阈值，才被认为是语义相似
SEMANTIC_SIMILARITY_THRESHOLD = 0.35
# 语义相似度计算的基本单元：按句子 ('sentence') 或按段落 ('paragraph') 'sentence' 通常更精细，但计算量更大
SEMANTIC_CHUNK_TYPE = 'sentence'
# 语义模型编码时的批量大小 (根据显存/内存调整)
SEMANTIC_ENCODE_BATCH_SIZE = 32
# 语义搜索返回的 Top K 个候选块（当不使用语义索引，而是直接计算时使用）
SEMANTIC_SEARCH_TOP_K = 10
# 最小语义块长度 (字符数)
MIN_SEMANTIC_CHUNK_LENGTH = 10
# 最大语义块长度 (字符数)
MAX_SEMANTIC_CHUNK_LENGTH = 150


# --- N-gram 相似度配置 (用于指标计算) ---
# 是否计算 N-gram TF-IDF 余弦相似度作为辅助指标
USE_NGRAM_SIMILARITY = True
# TF-IDF 使用的 N-gram 范围 (最小 N，最大 N)
NGRAM_RANGE = (5, 10)
# N-gram 分析器类型:
# 'word': 按词（需要分词）
# 'char': 按字符
# 'char_wb': 按字符，但在词边界处分割（推荐用于中文）
NGRAM_ANALYZER = 'char_wb'
# N-gram 高相似度阈值 (用于统计指标)
NGRAM_HIGH_SIMILARITY_THRESHOLD = 0.7


# --- 报告生成配置 ---
# 定义报告中“前部”和“后部”重复统计的范围（单位：字符数）
FRONT_PART_CHARS = 500 # 之前是按词算，改为按字符更明确
REAR_PART_CHARS = 500
# 报告中显示的单个来源片段的最大长度（字符数）
REPORT_FRAGMENT_MAX_LENGTH = 150
# 报告中复制比风险等级阈值 (%)
REPORT_RATIO_THRESHOLD_HIGH = 40.0 # 高风险阈值
REPORT_RATIO_THRESHOLD_MEDIUM = 10.0 # 中风险阈值
# 报告中风险等级对应的颜色
REPORT_COLOR_HIGH = "red"
REPORT_COLOR_MEDIUM = "orange"
REPORT_COLOR_LOW = "yellow"


# --- 查重的其他配置 ---
# 默认文本编码
DEFAULT_ENCODING = 'utf-8'
# 允许上传的文件扩展名 (用于 Web API)
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'docx'}
# 是否启用调试日志记录（可以在运行时覆盖）
DEBUG_LOGGING = False


# --- OCR 配置 ---
# 是否对 PDF 文件尝试使用 OCR 提取文本（当标准提取失败或效果不佳时）
USE_OCR_FOR_PDF = True
# 本地部署的 OCR API 端点 (接收 POST 请求，包含名为 'file' 的 PDF 文件)
INTERNAL_PDF_OCR_RETRY_ENDPOINT = "http://127.0.0.1:5055/process_pdf"
# OCR API 调用超时时间 (秒)
OCR_API_TIMEOUT = 300 # 5 分钟
# 当 PyMuPDF 提取的文本字符数少于此值时，尝试调用 OCR
MIN_TEXT_LENGTH_FOR_NON_OCR_PDF = 50

# --- 文本预处理配置 ---
# 分句器类型: 'regex' (使用正则表达式), 'ltp' (未来可支持LTP等模型)
# 当前版本仅 'regex' 生效
SENTENCE_SPLITTER_TYPE = 'regex'
# 大段落分割正则表达式 (用于 preprocessor.py 中的粗粒度分段)
PARAGRAPH_SPLIT_REGEX = r'\n\n+' # 默认按连续两个以上换行符分割
# 长句切分时，尝试在这些弱标点符号后切分 (用于优化后的正则分句)
WEAK_SENTENCE_DELIMITERS_REGEX = r'[；：，、]' # 中文分号、冒号、逗号、顿号
RE_WEAK_DELIMITERS = re.compile(WEAK_SENTENCE_DELIMITERS_REGEX)